package whf.framework.service;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

import whf.framework.dao.DAO;
import whf.framework.entity.Entity;
import whf.framework.exception.CreateException;
import whf.framework.exception.DAOException;
import whf.framework.exception.DuplicateException;
import whf.framework.exception.FindException;
import whf.framework.exception.NotFoundException;
import whf.framework.exception.RemoveException;
import whf.framework.exception.ServiceException;
import whf.framework.exception.UpdateException;
import whf.framework.i18n.ApplicationResource;
import whf.framework.log.Log;
import whf.framework.log.LogFactory;
import whf.framework.meta.Meta;
import whf.framework.meta.MetaFactory;
import whf.framework.meta.MetaNotFoundException;
import whf.framework.util.BeanFactory;
import whf.framework.util.BeanUtils;
import whf.framework.util.DateUtils;
import whf.framework.util.StringUtils;
import whf.framework.util.ThreadContext;
import whf.framework.util.Utils;

/**
 * @author wanghaifeng
 *
 */
@SuppressWarnings("unchecked")
public class ServiceImp<T extends Entity> extends SpringService implements Service<T>{
	private static Log log = LogFactory.getLog(ServiceImp.class);
	
	protected Class<T> entityClass;
	
	protected DAO<T> entityDAO;
	
	private Meta meta;
	/**
	 * @return 对应的dao对象
	 */
	protected DAO<T> getEntityDAO(){
		try{
			if(this.entityDAO == null){
				this.entityDAO = BeanFactory.getDao(this.getClass());
			}
		}catch(Exception e){
			log.error(e);
			throw new DaoNotFoundException(e);
		}
		return this.entityDAO;
	}

	/**
	 * @return 对应的元数据
	 */
	public Meta getMeta(){
		if(this.meta == null){
			this.meta = MetaFactory.findByServiceClass(getClass());
		}
		if(this.meta == null){
			MetaNotFoundException e = new MetaNotFoundException();
			log.error(e);
			throw e;
		}
		return this.meta;
	}
	
	/**
	 * @modify wanghaifeng Aug 25, 2006 12:55:47 PM
	 * @return 当前业务对象的boClass
	 */
	public Class<T> getEntityClass(){
		if(this.entityClass == null ){
			this.entityClass = this.getMeta().getModelClass();
		}
		return this.entityClass;
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#create(whf.framework.entity.IBaseBO)
	 */
	public void create(T entity) throws CreateException {
		if(entity.getCreateBy() == null){
			entity.setCreateBy(ThreadContext.getUserInUserContext());
		}
		entity.setCreateDate(DateUtils.getNow());
		this.getEntityDAO().create(entity);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#duplicate(whf.framework.entity.IBaseBO, int)
	 */
	public T duplicate(T entity, int deepth) throws DuplicateException, CreateException {
		if(entity == null) throw new DuplicateException(ApplicationResource.get("exception.illegal_arguments")) ;
		Map<String, Object> properties = Utils.newHashMap();
		properties.put("createBy", ThreadContext.getUserInUserContext());
		properties.put("id", new Long(0));
		T target = (T)BeanUtils.duplicate(entity, properties, deepth);
		this.entityDAO.create(target);
		return target;
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.service.Service#duplicate(whf.framework.entity.IBaseBO)
	 */
	public T duplicate(T entity) throws DuplicateException, CreateException {
		return this.duplicate(entity, 0);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findAll()
	 */
	public List<T> findAll() throws FindException {
		return this.getEntityDAO().findAll();
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findAll(int, int)
	 */
	public List<T> findAll(int start, int rowsPerPage) throws FindException {
		return this.getEntityDAO().findAll(start,rowsPerPage);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#findByPrimaryKey(java.io.Serializable)
	 */
	public T findByPrimaryKey(Serializable key) throws NotFoundException {
		return this.getEntityDAO().findByPrimaryKey(key);
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findByCode(java.lang.String)
	 */
	public T findByCode(String code) throws FindException{
		return this.getEntityDAO().findByCode(code);
	}

    /* (non-Javadoc)
     * @see whf.framework.service.FindService#find(java.lang.String)
     */
    public List<T> find(String query) throws FindException{
        return this.getEntityDAO().find(query);
    }

    /* (non-Javadoc)
     * @see whf.framework.service.FindService#find(java.lang.String, java.lang.Object)
     */
    public List<T> find(String query,Object arg) throws FindException{
        return this.getEntityDAO().find(query,arg);
    }

    /* (non-Javadoc)
     * @see whf.framework.service.FindService#find(java.lang.String, java.lang.Object[])
     */
    public List<T> find(String query,Object[] args) throws FindException{
        return this.getEntityDAO().find(query,args);
    }

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#remove(whf.framework.entity.IBaseBO)
	 */
	public void remove(T entity) throws RemoveException {
		this.getEntityDAO().remove(entity);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#removeByPrimaryKey(java.io.Serializable)
	 */
	public void removeByPrimaryKey(Serializable key) throws RemoveException, NotFoundException {
		T entity = this.getEntityDAO().findByPrimaryKey(key);
		this.remove(entity);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#removeByPrimaryKey(java.io.Serializable[])
	 */
	public void removeByPrimaryKey(Serializable[] keys) throws RemoveException, NotFoundException {
		for(Serializable key: keys){
			T entity = this.getEntityDAO().findByPrimaryKey(key);
			this.remove(entity);
		}
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#update(whf.framework.entity.IBaseBO)
	 */
	public void update(T entity) throws UpdateException {
		if(entity.getUpdateBy() == null){
			entity.setUpdateBy(ThreadContext.getUserInUserContext());
		}
		entity.setUpdateDate(DateUtils.getNow());
		this.getEntityDAO().update(entity);
	}

    /* (non-Javadoc)
     * @see whf.framework.service.FindService#list(java.lang.String, int, int)
     */
    public List<T> list(String queryString, int start, int rowsPerPage){
        return getEntityDAO().list(queryString,start,rowsPerPage);
    }

    /* (non-Javadoc)
     * @see whf.framework.service.FindService#list(java.lang.String, java.lang.Object[], int, int)
     */
    public List<T> list(String queryString, Object[] paramValues, int start, int rowsPerPage){
        return getEntityDAO().list(queryString,paramValues,start,rowsPerPage);
    }

    /* (non-Javadoc)
     * @see whf.framework.service.FindService#list(java.lang.String, java.lang.String[], java.lang.Object[], int, int)
     */
    public List<T> list(String queryString, String[] paramNames, Object[] paramValues, int start, int rowsPerPage){
        return getEntityDAO().list(queryString,paramNames,paramValues,start,rowsPerPage);
    }

    /* (non-Javadoc)
     * @see whf.framework.service.FindService#getRowCount(java.lang.String)
     */
    public int getRowCount(String conditionString) throws DAOException {
		return getEntityDAO().getRowCount(conditionString);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#getRowCount(java.lang.String, java.lang.Object[])
	 */
	public int getRowCount(String fromAndWhere,Object[] params) throws FindException{
        return getEntityDAO().getRowCount(fromAndWhere,params);
    }

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#invokeMethod(java.lang.String, java.lang.Class[], java.lang.Object[])
	 */
	public Object invokeMethod(String methodName,Class[] types, Object[] params) throws ServiceException, NoSuchMethodException {
		Class clazz = this.getClass();
		try{
			Method method = clazz.getMethod(methodName, types);
			Object result = method.invoke(this,params);
			return result;
		}catch (NoSuchMethodException ne){
			log.error(this, ne);
			throw ne;
		}catch(Exception e){
			log.error(this, e);
			throw new ServiceException(e);
		}
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.QueryService#query(java.lang.String, int, int)
	 */
	public List<T> query(String propertyString, int start, int rowsPerPage) throws FindException {
		return getEntityDAO().query(propertyString, start, rowsPerPage);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.QueryService#query(java.lang.String)
	 */
	public List<T> query(String propertyString) throws FindException {
		return getEntityDAO().query(propertyString);
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.service.QueryService#queryWithoutLazy(java.lang.String)
	 */
	public List<T> queryWithoutLazy(String queryString) throws FindException{
		return getEntityDAO().queryWithoutLazy(queryString);
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.service.QueryService#queryWithoutLazy(java.lang.String, int, int)
	 */
	public List<T> queryWithoutLazy(String queryString, int start, int pageSize) throws FindException{
		return getEntityDAO().queryWithoutLazy(queryString, start, pageSize);
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.service.QueryService#getQueryRowCount(java.lang.String)
	 */
	public int getQueryRowCount(String propertyString) throws FindException{
		return getEntityDAO().getQueryRowCount(propertyString);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#removeByPrimaryKey(long)
	 */
	public void removeByPrimaryKey(long key) throws RemoveException {
		try{
			T entity = this.getEntityDAO().findByPrimaryKey(key);
			this.remove(entity);
		}catch(Exception e){
			throw new RemoveException(e);
		}
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.Service#removeByPrimaryKey(long[])
	 */
	public void removeByPrimaryKey(long[] keys) throws RemoveException, NotFoundException {
		try{
			for(long key : keys){
				T entity = this.getEntityDAO().findByPrimaryKey(key);
				this.remove(entity);
			}
		}catch(Exception e){
			throw new RemoveException(e);
		}
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findWithoutLazy(java.lang.String)
	 */
	public List<T> findWithoutLazy(String queryString) throws FindException{
		return this.getEntityDAO().findWithoutLazy(queryString);
	}
	
	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findWithoutLazy(java.lang.String, java.lang.Object[])
	 */
	public List<T> findWithoutLazy(String queryString, Object[] params) throws FindException{
		return this.getEntityDAO().findWithoutLazy(queryString, params);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findByPrimaryKeyWithoutLazy(java.io.Serializable)
	 */
	public T findByPrimaryKeyWithoutLazy(Serializable key) throws NotFoundException {
		return this.getEntityDAO().findByPrimaryKeyWithoutLazy(key);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findByProperty(java.util.Map, int, int)
	 */
	public List<T> findByProperty(Map<String, Object> properties, int start, int pageSize) throws FindException {
		return this.getEntityDAO().findByProperties(properties, start, pageSize);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findWithoutLazy(java.lang.String, int, int)
	 */
	public List<T> findWithoutLazy(String queryString, int start, int pageSize) throws FindException {
		return this.getEntityDAO().findWithoutLazy(queryString, start, pageSize);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findWithoutLazy(java.lang.String, java.lang.Object, int, int)
	 */
	public List<T> findWithoutLazy(String queryString, Object arg, int start, int pageSize) throws FindException {
		return this.getEntityDAO().findWithoutLazy(queryString, arg, start, pageSize);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findWithoutLazy(java.lang.String, java.lang.Object)
	 */
	public List<T> findWithoutLazy(String queryString, Object arg) throws FindException {
		return this.getEntityDAO().findWithoutLazy(queryString, arg);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findWithoutLazy(java.lang.String, java.lang.Object[], int, int)
	 */
	public List<T> findWithoutLazy(String queryString, Object[] params, int start, int pageSize) throws FindException {
		return this.getEntityDAO().findWithoutLazy(queryString, params, start, pageSize);
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findAllWithoutLazy()
	 */
	public List<T> findAllWithoutLazy() throws FindException {
		return this.getEntityDAO().findWithoutLazy(" from "+this.getEntityClass().getName() );
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#findAllWithoutLazy(int, int)
	 */
	public List<T> findAllWithoutLazy(int start, int pageSize) throws FindException {
		return this.getEntityDAO().findWithoutLazy(" from "+this.getEntityClass().getName(), start, pageSize );
	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#searchByBO(whf.framework.entity.IBaseBO)
	 */
//	public List<T> searchByBO(T condition, int start, int pageSize) throws FindException {
//		if(condition == null){
//			return EMPTY_LIST;
//		}
//		Meta meta = this.getMeta();
//		Map<String, Object> mapCondition = Utils.newHashMap();
//		Set<IProperty> properties = meta.getProperties();
//		for(IProperty prop : properties){
//			String name = prop.getName();
//			try{
//				Object value = BeanUtils.getProperty(condition, name);
//				mapCondition.put(name, value);
//			}catch(Exception e){
//				continue;
//			}
//		}
//		return this.referenceDAO.findByProperties(mapCondition, start, pageSize);
//	}

	/* (non-Javadoc)
	 * @see whf.framework.service.FindService#searchByBOWithoutLazy(whf.framework.entity.IBaseBO, int, int)
	 */
//	public List<T> searchByBOWithoutLazy(T condition, int start, int pageSize) throws FindException {
//		if(condition == null){
//			return EMPTY_LIST;
//		}
//		Meta meta = this.getMeta();
//		Map<String, Object> mapCondition = Utils.newHashMap();
//		Set<IProperty> properties = meta.getProperties();
//		for(IProperty prop : properties){
//			String name = prop.getName();
//			try{
//				Object value = BeanUtils.getProperty(condition, name);
//				mapCondition.put(name, value);
//			}catch(Exception e){
//				continue;
//			}
//		}
//		return this.referenceDAO.findByPropertiesWithoutLazy(mapCondition, start, pageSize);
//	}

	/**
	 * 一个缺省的树实现方法，并非所有的service均可以使用这个方法，
	 * 只有那些业务对象实现了ITreeItem的对象的服务才可以
	 * @param parent
	 * @param queryString
	 * @return
	 */
	public List<T> findChildren(T parent, String queryString){
		List<T> list = null;
		StringBuilder sb = new StringBuilder();
		try{
			if(parent == null){
				sb.append(" where t.parent is null ");
				if(!StringUtils.isEmpty(queryString)){
					sb.append(" and ").append(queryString);
				}
				list = find(sb.toString());
			}else{
				sb.append(" where t.parent = ?");
				if(!StringUtils.isEmpty(queryString)){
					sb.append(" and ").append(queryString);
				}
				list = find(sb.toString(), parent);
			}
		}catch(FindException e){
			log.error(this, e);
		}
		return list;
	}

}
